﻿using FanMotionWink;
using EmbedIO;
using EmbedIO.WebApi;
using System;
using EmbedIO.Actions;
using Swan.Logging;
using System.Diagnostics;
using System.Text.Json;
using EmbedIO.Files;

namespace FanMotionWink
{

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            ProcessUtils.AutoWork();

            InitWebAndEngineAppliction();


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyCustomApplicationContext());
        }

        static string svcAddr = "";
        public static string SvcAddrDesc = "";
        public static string SvcAddr => svcAddr;
        static WebServer galobalWebServer = null;
        static CancellationTokenSource galobalWebServerCancle = new CancellationTokenSource();

        public static void ExitSvc()
        {
            galobalWebServerCancle.Cancel();
            galobalWebServer.Dispose();
        }

        /// <summary>
        /// Defines the entry point of the application.
        /// </summary>
        /// <param name="args">The arguments.</param>
        static void InitWebAndEngineAppliction()
        {
            // init
            HardwareUtils.InitUpdateLoop();
            StorageInstance.InitLoad();
            FanUtils.InitUpdateInterval();

            for (ushort portToTry = 51001; portToTry < 65001; portToTry++)
            {
                try
                {
                    svcAddr = "http://127.0.0.1:" + portToTry;
                    SvcAddrDesc = ":" + portToTry;
                    galobalWebServer = CreateWebServer();
                    galobalWebServer.RunAsync(galobalWebServerCancle.Token);
                    return;
                }
                catch (System.Net.HttpListenerException)
                {
                    continue;
                }
            }
        }


        public class apiProfileSetCurvePointsReq
        {
            public string id { get; set; }
            public Pos[] curvePoints { get; set; }

            public class Pos
            {
                public float X { get; set; }
                public float Y { get; set; }
            }
        }
        public class apiProfileSetFlagReq
        {
            public string id { get; set; }
            public bool? enableControl { get; set; }
            public bool? hideInMain { get; set; }
        }
        public class apiGlobalSettingSetFlagReq
        {
            public bool? enableControl { get; set; }
            public bool? startupOnWin { get; set; }

        }

        // Create and configure our web server.
        private static WebServer CreateWebServer()
        {
            var server = new WebServer(o => o.WithUrlPrefix(svcAddr).WithMode(HttpListenerMode.EmbedIO))
                .WithLocalSessionManager()
                .WithStaticFolder("/static", "./static", true, m => m.WithContentCaching(true)) // Add static files after other modules to avoid conflicts
                .WithAction("/api/fan/profile", HttpVerbs.Any, ctx =>
                {
                    StorageInstance.ReloadFromDiskFile();
                    return ctx.SendDataAsync(new
                    {
                        Data = StorageInstance.Instance?.FanControllerList
                    });
                })
                .WithAction("/api/fan/list", HttpVerbs.Any, ctx => ctx.SendDataAsync(new
                {
                    Data = FanUtils.GetFanItemModelList()
                }))
                .WithAction("/api/tempature/list", HttpVerbs.Any, ctx => ctx.SendDataAsync(new
                {
                    Data = FanUtils.GetTempatureList()
                }))
                .WithAction("/api/profile/setCurvePoints", HttpVerbs.Any, async ctx =>
                {
                    var reqBody = await ctx.GetRequestBodyAsStringAsync();
                    var reqObj = JsonSerializer.Deserialize<apiProfileSetCurvePointsReq>(reqBody);


                    StorageInstance.Instance.FindOrCreate(reqObj.id)
                    .curvePoints = reqObj
                    .curvePoints.Select(item => new CurvePoint(item.X, item.Y)).ToList();
                    StorageInstance.RefreshSave();


                    await ctx.SendDataAsync(new
                    {
                        Success = true,
                    });
                })
                .WithAction("/api/profile/setFlag", HttpVerbs.Any, async ctx =>
                {
                    var reqBody = await ctx.GetRequestBodyAsStringAsync();
                    var reqObj = JsonSerializer.Deserialize<apiProfileSetFlagReq>(reqBody);


                    if (reqObj.enableControl.HasValue)
                    {
                        StorageInstance.Instance.FindOrCreate(reqObj.id).IsControl = reqObj.enableControl.Value;
                    }
                    if (reqObj.hideInMain.HasValue)
                    {
                        StorageInstance.Instance.FindOrCreate(reqObj.id).HideInMain = reqObj.hideInMain.Value;
                    }
                    StorageInstance.RefreshSave();


                    await ctx.SendDataAsync(new
                    {
                        Success = true,
                    });
                })
                .WithAction("/api/globalSetting/get", HttpVerbs.Any, ctx =>
                {
                    StorageInstance.ReloadFromDiskFile();
                    return ctx.SendDataAsync(new
                    {
                        enableControl = StorageInstance.Instance?.GlobalEnable,
                        startupOnWin = StorageInstance.Instance?.StartupOnWin,
                    });
                })
                .WithAction("/api/globalSetting/setFlag", HttpVerbs.Any, async ctx =>
                {
                    var reqBody = await ctx.GetRequestBodyAsStringAsync();
                    var reqObj = JsonSerializer.Deserialize<apiGlobalSettingSetFlagReq>(reqBody);

                    if (reqObj.enableControl.HasValue)
                    {
                        StorageInstance.Instance.GlobalEnable = reqObj.enableControl.Value;
                    }
                    if (reqObj.startupOnWin.HasValue)
                    {
                        StorageInstance.Instance.StartupOnWin = reqObj.startupOnWin.Value;
                        if (StorageInstance.Instance.StartupOnWin)
                        {
                            ProcessUtils.ReistAsAdminAutoRunOn();
                        }
                        else
                        {
                            ProcessUtils.ReistAsAdminAutoRunOff();
                        }
                    }
                    StorageInstance.RefreshSave();

                    await ctx.SendDataAsync(new
                    {
                        Success = true,
                    });
                })
                .WithAction("/api/app/debug", HttpVerbs.Any, ctx => ctx.SendDataAsync(new
                {
                    Name = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
                }))
                .WithAction("/api/app/debug_start", HttpVerbs.Any, ctx =>
                {
                    //ProcessUtils.StartProcessAsCurrentUser(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, "some");
                    //ProcessUtils2.StartProcessAndBypassUAC(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, "some", out var x1);
                    return ctx.SendDataAsync(new
                    {
                        Name = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName,
                    });
                })
                .WithAction(HttpVerbs.Get, ctx =>
                {
                    // 可以优化读取
                    var content = File.ReadAllText("./static/vue/index.html");
                    return ctx.SendStringAsync(content, "text/html; charset=utf-8", System.Text.Encoding.UTF8);
                })
                ;

            // Listen for state changes.
            server.StateChanged += (s, e) => $"WebServer New State - {e.NewState}".Info();
            return server;
        }
    }


    public class MyCustomApplicationContext : ApplicationContext
    {
        private NotifyIcon trayIcon;

        public string enableText(bool enable)
        {
            if (enable) return "启用中";
            return "已停用（点击启用） ";
        }
        public string enableStartWithWinText(bool enable)
        {
            if (enable) return "随系统启动";
            return "不随系统启动（点击启用） ";
        }
        public Color enableColor(bool enable)
        {
            if (enable) return Color.Green;
            return Color.RebeccaPurple;
            //return Color.PaleVioletRed;
        }

        private void openStatus()
        {
            //System.Diagnostics.Process.Start("http://blog.csdn.net/testcs_dn"); 
            string target = "http://www.microsoft.com";
            //Use no more than one assignment when you test this code.
            //string target = "ftp://ftp.microsoft.com";
            //string target = "C:\\Program Files\\Microsoft Visual Studio\\INSTALL.HTM";
            try
            {
                string url = "https://www.baidu.com/s?wd=what";
                url = Program.SvcAddr;
                Process p = new Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;    //不使用shell启动
                p.StartInfo.RedirectStandardInput = true;//喊cmd接受标准输入
                p.StartInfo.RedirectStandardOutput = false;//不想听cmd讲话所以不要他输出
                p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
                p.StartInfo.CreateNoWindow = true;//不显示窗口
                p.Start();
                //向cmd窗口发送输入信息 后面的&exit告诉cmd运行好之后就退出
                p.StandardInput.WriteLine("start " + url + "&exit");
                p.StandardInput.AutoFlush = true;
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();

                //System.Diagnostics.Process.Start("start", " microsoft-edge:http://www.cnn.com");
            }
            catch (System.Exception other)
            {
                MessageBox.Show(other.Message);
            }
        }


        ToolStripMenuItem globalEnableItem;
        ToolStripMenuItem globalStartupWithWinItem;
        void ToggleEnableSwitch()
        {
            globalEnableItem.Checked = !globalEnableItem.Checked;

            // 全局启用停用
            {
                globalEnableItem.ForeColor = enableColor(globalEnableItem.Checked);
                globalEnableItem.Text = enableText(globalEnableItem.Checked);
                ChangeTrayIcon(globalEnableItem.Checked);
            }
            StorageInstance.Instance.GlobalEnable = globalEnableItem.Checked;
            StorageInstance.RefreshSave();
        }

        public ContextMenuStrip CreateContextMenuStripMine()
        {
            // Add the default menu options.
            var menu = new ContextMenuStrip();
            ToolStripMenuItem item;
            ToolStripSeparator sep;

            globalEnableItem = new ToolStripMenuItem
            {
                Text = enableText(StorageInstance.Instance?.GlobalEnable ?? false),
                ForeColor = enableColor(StorageInstance.Instance?.GlobalEnable ?? false),
                Checked = StorageInstance.Instance?.GlobalEnable ?? false,
            };
            globalEnableItem.Click += new EventHandler((e, s) =>
            {
                ToggleEnableSwitch();
            });
            menu.Items.Add(globalEnableItem);
            var tttt = new System.Windows.Forms.Timer();
            tttt.Interval = 500;
            tttt.Tick += (e, s) =>
            {
                if (trayIcon != null)
                {
                    globalEnableItem.Checked = StorageInstance.Instance.GlobalEnable;
                    ChangeTrayIcon(globalEnableItem.Checked);


                    globalStartupWithWinItem.Checked = StorageInstance.Instance.StartupOnWin;
                    globalStartupWithWinItem.Text = enableStartWithWinText(StorageInstance.Instance?.StartupOnWin ?? false);
                    globalStartupWithWinItem.ForeColor = enableColor(StorageInstance.Instance?.StartupOnWin ?? false);
                }
            };

            {
                globalStartupWithWinItem = new ToolStripMenuItem
                {
                    Text = enableStartWithWinText(StorageInstance.Instance?.StartupOnWin ?? false),
                    ForeColor = enableColor(StorageInstance.Instance?.StartupOnWin ?? false),
                    Checked = StorageInstance.Instance?.StartupOnWin ?? false,
                };
                globalStartupWithWinItem.Click += new EventHandler((e, s) =>
                {
                    StorageInstance.Instance.StartupOnWin = !StorageInstance.Instance.StartupOnWin;


                    if (StorageInstance.Instance.StartupOnWin)
                    {
                        ProcessUtils.ReistAsAdminAutoRunOn();
                    }
                    else
                    {
                        ProcessUtils.ReistAsAdminAutoRunOff();
                    }


                    StorageInstance.RefreshSave();
                    globalStartupWithWinItem.Checked = StorageInstance.Instance.StartupOnWin;
                    globalStartupWithWinItem.Text = enableStartWithWinText(StorageInstance.Instance?.StartupOnWin ?? false);
                    globalStartupWithWinItem.ForeColor = enableColor(StorageInstance.Instance?.StartupOnWin ?? false);
                });

                if (StorageInstance.Instance.StartupOnWin)
                {
                    ProcessUtils.ReistAsAdminAutoRunOn();
                }
                else
                {
                    ProcessUtils.ReistAsAdminAutoRunOff();
                }

                menu.Items.Add(globalStartupWithWinItem);
            }

            tttt.Start();

            // About.
            item = new ToolStripMenuItem
            {
                Text = "服务状态 Status " + Program.SvcAddrDesc,
                //Image = Resources.data_green1
            };
            item.Click += new EventHandler((e, s) =>
            {
                openStatus();

            });

            menu.Items.Add(item);

            // Separator.
            sep = new ToolStripSeparator();
            menu.Items.Add(sep);

            item = new ToolStripMenuItem
            {
                Name = "mnuClose",
                Text = "Close",
                //Image = Resources.data_down
            };

            item.Click += new EventHandler((e, s) => { Exit(e, s); });

            menu.Items.Add(item);
            return menu;
        }

        void ChangeTrayIcon(bool enable)
        {
            trayIcon.Icon = enable ? globalIconOn : globalIconNormal;
        }
        Icon globalIconNormal;
        Icon globalIconOn;

        public MyCustomApplicationContext()
        {
            globalIconNormal = Icon.FromHandle(((Bitmap)Image.FromFile("./static/vue/fan-icon.png")).GetHicon());
            globalIconOn = Icon.FromHandle(((Bitmap)Image.FromFile("./static/vue/fan-icon-on.png")).GetHicon());

            // Initialize Tray Icon
            trayIcon = new NotifyIcon()
            {
                ContextMenuStrip = CreateContextMenuStripMine(),
                Icon = globalIconNormal,
                Visible = true,
                BalloonTipText = "单击打开，打开菜单，中间开关（Switch）",
            };
            trayIcon.DoubleClick += (s, e) => { openStatus(); };
            trayIcon.Click += (s, e) =>
            {
                var ee = e as System.Windows.Forms.MouseEventArgs;
                if (ee != null && ee.Button == MouseButtons.Middle)
                {
                    ToggleEnableSwitch();
                }
            };
        }

        void Exit(object sender, EventArgs e)
        {
            // Hide tray icon, otherwise it will remain shown until user mouses over it
            trayIcon.Visible = false;
            Program.ExitSvc();
            Application.Exit();
            Process.GetCurrentProcess().Kill();
        }
    }




}
